#ifndef AIG_H
#define AIG_H

#include "aigType.h"
#include <vec.h>
#include <google/dense_hash_map>

class CktName;
extern uint64_t hash64shift(uint64_t a);

/**
@brief a 1 level structure hashed aig( and invertor ) circuit, 

this circuit is construct by createBase , createAND function 
*/
class StrashAIG : public vec<AigNode> 
{
   /// comparing sorted pair signed index 
   struct StrashEq {
      inline bool operator()( AigNode p,AigNode q )const{return p.key==q.key;} 
   };
   /// hash by signed index 
   struct Strash_key{
      inline size_t operator()( AigNode a )const{return hash64shift(a.key);} 
   };
   typedef google::dense_hash_map<AigNode , unsigned, Strash_key,StrashEq> AigHash;

   private:
   AigHash          _hash; ///< Hash with same 2-input
   void             read_initialization( unsigned I , unsigned L , unsigned O , unsigned M = 0 );///< initialize allocation 

   public:

   unsigned         _andFlag; ///< the start  and gates.
   unsigned         _ppiFlag; ///< the start index of ppi , ( number of pi is ppiFlag-1)
   vec<AigLit>      _po;      ///< ppo and po , start from ppo and continues po 

   StrashAIG();
   bool read_aig (const char * str , CktName * names = NULL );              ///< read aig from file 
   bool write_aig(const char * str , CktName * names = NULL)const;          ///< write aig to file 
   void write_dot(const char * str , unsigned char * color = NULL )const;   ///< write the circuit in dot format

   //--- Atomic construction
   void     createBase(){ assert( _hash.size() == 0 ); push(); }            ///< input construction

   AigLit   createAND( AigLit a , AigLit b );                               ///< construction and gate
   void     pop_back(){ _hash.erase( last() ) ; pop() ; }                   ///< erase the last gate 

   AigLit   pseudo_createAND( AigLit a , AigLit b );                        ///< create the gate but not hash inserting (speed consider)
   void     pseudo_pop_back(){ pop(); }                                     ///< match to pseudo_createAND
   void     realize_and(unsigned i ){ for(;i!=size();++i)_hash.insert(AigHash::value_type(data[i],i));} ///< match to pseudo_createAND

   AigLit   test_createAND( AigLit a , AigLit b )const;                     ///< test the gates is ready inside (example , <1,x> is constructed )
   bool     created( AigNode n )const{ return _hash.find(n) != _hash.end() ;}///< test the node is inside the hash
   bool     isPI( unsigned n )const{return n < _andFlag ; }                 ///< isPI

   void     report()const;                                                  ///< size reporting 
   bool     check ()const;                                                  ///< basic check for io count
   unsigned andSize()const{return _hash.size() ;}                           ///< gate in hash 
};

#endif
